package org.rc.dao;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.files.AppEngineFile;
import com.google.appengine.api.files.FileReadChannel;
import com.google.appengine.api.files.FileServiceFactory;
import org.rc.model.ResultsFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * Created by IntelliJ IDEA.
 * User: dokeeffe
 * Date: 24/02/2012
 * Time: 21:15
 * To change this template use File | Settings | File Templates.
 */
public class ResultsFileDao extends GenericDao<ResultsFile> {

    private byte LINE_FEED = "\n".getBytes()[0];
    private static final Logger LOGGER = LoggerFactory.getLogger(ResultsFileDao.class);

    /**
     * Constructor
     */
    public ResultsFileDao() {
        super(ResultsFile.class);
    }

    /**
     * Load a section of a results file from the blobstore.
     * Starting from the fromLine passed. The limit passed will tbe the number of lines. returned.
     * It is asumed lines are seperated by a LINE_FEED
     *
     * @param resultsFile
     * @param fromLine
     * @param limit
     * @return a byte array of the blob contents
     * @throws java.io.IOException
     * @throws java.io.FileNotFoundException
     */
    public byte[] LoadBlobResults(ResultsFile resultsFile, long fromLine, long limit) throws IOException, FileNotFoundException {
        BlobKey bk = new BlobKey(resultsFile.getBlobKey());
        AppEngineFile gaeFile = FileServiceFactory.getFileService().getBlobFile(bk);
        FileReadChannel ch = FileServiceFactory.getFileService().openReadChannel(gaeFile, true);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        long linesWritten = 0;
        long lineNumber = 1;
        try {
            byte[] barray = new byte[1024];
            ByteBuffer bb = ByteBuffer.wrap(barray);
            int nRead;
            outer:
            while ((nRead = ch.read(bb)) != -1) {
                for (int i = 0; i < nRead; i++) {
                    try {
                        if (barray[i] == LINE_FEED && lineNumber < fromLine) {
                            lineNumber++;
                            continue;
                        }
                        if (lineNumber >= fromLine) {
                            out.write(barray[i]);
                            if (barray[i] == LINE_FEED) {
                                linesWritten++;
                                if (linesWritten >= limit) {
                                    break outer;
                                }
                            }
                        }
                    } catch (Exception e) {
                        LOGGER.error("error writing to buffer. ",e);
                    }
                }
                bb.clear();
            }
        } catch (IOException e) {
            LOGGER.error("Exception reading from blobstore",e);
        } finally {
            ch.close();
        }
        byte[] bytes = out.toByteArray();
        return bytes;
    }
}
